/*
 * Copyright 2008 The Microlog project @sourceforge.net
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.sf.microlog.midp.appender.s3;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;

import net.sf.microlog.core.Appender;
import net.sf.microlog.core.CyclicBuffer;
import net.sf.microlog.core.Level;
import net.sf.microlog.core.appender.AbstractAppender;

/**
 * The <code>S3BufferAppender</code> logs to a <code>CyclicBuffer</code>.
 * When a message is logged at the specified log level or above, the buffer is
 * stored as an S3 Object (i.e. as file).
 * 
 * @author Johan Karlsson (johan.karlsson@jayway.se)
 */
public class S3BufferAppender extends AbstractAppender {

	public static final String DEFAULT_FILE_NAME = "Microlog.txt";

	public static final String FILE_NAME_PROPERTY = "net.sf.microlog.appender.S3BufferAppender.fileName";
	
	public static final String[] PROPERTY_NAMES = { "fileName"};

	public static final String[] DEFAULT_VALUES = { DEFAULT_FILE_NAME };

	private CyclicBuffer buffer;

	/**
	 * This is the trigger level that triggers the storing of the log.
	 */
	private Level triggerLevel = Level.ERROR;

	/**
	 * This is the log service that is used for storing the file on S3.
	 */
	private S3LogService logService;

	private String fileName = DEFAULT_FILE_NAME;

	/**
	 * Create an <code>S3BufferAppender</code>.
	 */
	public S3BufferAppender() {
		buffer = new CyclicBuffer();
		logService = new S3SOAPLogService();
	}

	/**
	 * Set the access key ID for your Amazon Web Service (AWS) account.
	 * 
	 * @param accessKeyID
	 *            the access key id to use.
	 */
	public void setAccessKeyID(String accessKeyID) {
		logService.setAccessKeyID(accessKeyID);
	}

	/**
	 * Set the secret access key for your Amazon Web Service (AWS) account.
	 * 
	 * @param secretAccessKey
	 *            the access key to use.
	 */
	public void setSecretAccessKey(String secretAccessKey) {
		logService.setSecretAccessKey(secretAccessKey);
	}

	/**
	 * Get the level that is used for trigger a store on the server.
	 * 
	 * @return the triggerLevel
	 */
	public Level getTriggerLevel() {
		return triggerLevel;
	}

	/**
	 * Set the level that is used for trigger a store on the server.
	 * 
	 * @param triggerLevel
	 *            the triggerLevel to set
	 */
	public void setTriggerLevel(Level triggerLevel) {
		this.triggerLevel = triggerLevel;
	}
	
	

	/**
	 * @return the fileName
	 */
	synchronized public String getFileName() {
		return fileName;
	}

	/**
	 * @param fileName the fileName to set
	 */
	synchronized public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	/**
	 * @see net.sf.microlog.core.appender.AbstractAppender#clear()
	 */
	public void clear() {
		buffer.clear();
	}

	/**
	 * @see net.sf.microlog.core.appender.AbstractAppender#open()
	 */
	public void open() throws IOException {
		logOpen = true;
	}

	/**
	 * @see net.sf.microlog.core.appender.AbstractAppender#close()
	 */
	public void close() throws IOException {
		logOpen = false;
	}

	/**
	 * @see net.sf.microlog.core.Appender#getLogSize()
	 */
	public long getLogSize() {
		return buffer.length();
	}
	

	/**
	 * @see net.sf.microlog.core.appender.AbstractAppender#doLog(String,
	 *      String, long, net.sf.microlog.core.Level, java.lang.Object, java.lang.Throwable)
	 */
	synchronized public void doLog(String clientID, String name, long time, Level level, Object message, Throwable t) {
		if (logOpen && formatter != null) {
			buffer.add(formatter.format(null, name, time, level, message, t));
		}

		// Check if we shall store the log
		if (level.toInt() >= triggerLevel.toInt()) {
			final byte[] logData = getLogData();
			new Thread(new Runnable() {
				public void run() {
					logService.storeLog(getFileName(), logData);
				}
			}).start();
		}
	}

	private synchronized byte[] getLogData() {

		// Get the data from the CyclicBuffer
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		PrintStream printStream = new PrintStream(baos);

		int logLength = buffer.length();
		for (int index = 0; index < logLength; index++) {
			Object currentData = buffer.get();
			printStream.println(currentData);
		}

		return baos.toByteArray();
	}
	
	/**
	 * @see Appender#getPropertyNames()
	 */
	public String[] getPropertyNames() {
		return PROPERTY_NAMES;
	}
	
	/**
	 * @see Appender#setProperty(String, String)
	 */
	public void setProperty(String name, String value)
			throws IllegalArgumentException {
		// TODO Auto-generated method stub
		
	}

}
